package evs.gateway;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import evs.location.EntityDom;
import evs.location.EvsException;
import evs.security.SecureServlet;

public class GatewayServlet extends SecureServlet
{
    private static final long serialVersionUID = -8149061350556429024L;

    private String _indexUrl;
    
    @Override
    public void init() throws ServletException
    {
        super.init();

        _http.addCustomHeaderField( "x-source-service", this.getServletName() );
        
        String configFilePath = this.getInitParameter( "gateway-config-file" );

        InputStream stream = this.getClass().getClassLoader().getResourceAsStream( configFilePath );

        if ( stream == null )
        {
            throw new ServletException( "Could not find configuration file for " + this.getClass().getSimpleName() +"!" );
        }

        try
        {
            Document xml = Util.getDocumentFromStream( stream );

            NodeList nodes = xml.getElementsByTagName( "index-url" );

            if ( nodes.getLength() != 1 )
            {
                throw new ServletException( this.getClass().getSimpleName() +
                                " - Config file does not contain url of LocationIndex!" );
            }

            _indexUrl = nodes.item( 0 ).getTextContent();
        }
        catch ( Exception e )
        {
            throw new ServletException( e );
        }
        finally
        {
            if ( stream != null )
            {
                try
                {
                    stream.close();
                }
                catch ( IOException e )
                {
                }
            }
        }
    }

    @Override
    protected void doPost( HttpServletRequest request, HttpServletResponse response )
                    throws ServletException, IOException
    {
        try
        {
            _checkAllowRequest( request );
            
            if ( request.getHeader( "x-source-service" ) == null )
            {
                throw new EvsException( HttpServletResponse.SC_BAD_REQUEST, "x-source-service header missing" );
            }

            String searchTerm = _getSearchTerm( request );
            
            List<String> storages = _getStorages();

            EntityDom results = new EntityDom();
            results.name = "results";

            for ( String storageURL : storages )
            {
                EntityDom storageResults = _getSearchResults( storageURL, searchTerm );
                ResultMerger.merge( storageResults, results, "Person" );
            }

            try
            {
                String plainTextResponse = "application/json".equals( request.getContentType() ) ?
                                results.toJson() : results.toXML();
                
                String encryptedResponse = _securityManager.encrypt( plainTextResponse, 
                                request.getHeader( "x-source-service" ) );
                                
                response.getWriter().write( encryptedResponse );
            }
            catch ( IOException e )
            {
                throw new ServletException( e );
            }
        }
        catch ( EvsException e )
        {
            response.sendError( e.HTTP_CODE, e.getMessage() );
        }
    }

    protected EntityDom _getSearchResults( String storageURL, String searchTerm )
                    throws ServletException
    {
        try
        {
            String searchUrl = _createSearchUrl( storageURL, searchTerm );
            String response = _http.get( searchUrl, "application/xml" );
            
            return EntityDom.fromXML( response );
        }
        catch ( IOException e )
        {
            throw new ServletException( e );
        }
        catch ( EvsException e )
        {
            throw new ServletException( e );
        }
    }

    protected String _createSearchUrl( String storageURL, String searchTerm )
    {
        return storageURL + "/Fulltext-Search/Persons?term=" + searchTerm;
    }

    private String _getSearchTerm( HttpServletRequest request ) throws EvsException
    {
        try
        {
            String encrypted = request.getReader().readLine();
            String plainText = _securityManager.decryptWithPrivateKey( encrypted );
            
            if ( !plainText.startsWith( "searchTerm=" ) )
            {
                throw new EvsException( HttpServletResponse.SC_BAD_REQUEST, "Couldn't decrypt request." );
            }
            
            return plainText.substring( plainText.indexOf( "=" ) + 1 );
        }
        catch ( IOException e )
        {
            throw new EvsException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage() );
        }
    }
    
    protected String _getIndexUrl() throws MalformedURLException
    {
        return _indexUrl;
    }

    private List<String> _getStorages() throws ServletException
    {
        try
        {
            String response = _http.get( _getIndexUrl(), "application/xml" );
            Document xml = Util.getDocumentFromString( response );
            
            NodeList nodes = xml.getElementsByTagName( "url" );

            ArrayList<String> urls = new ArrayList<String>();

            for ( int i = 0; i < nodes.getLength(); ++i )
                urls.add( nodes.item( i ).getTextContent() );

            return urls;
        }
        catch ( Exception e )
        {
            throw new ServletException( e );
        }
    }
    
    @Override 
    protected boolean _allowOnlyLocalAccess() { return false; }
}
